/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=2 sw=2 et tw=78: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. *//* arena allocation for the frame tree and closely-related objects */#include"nsPresArena.h"#include"mozilla/Poison.h"#include"nsDebug.h"#include"nsArenaMemoryStats.h"#include"nsPrintfCString.h"#include"GeckoStyleContext.h"#include"FrameLayerBuilder.h"#include"mozilla/ArrayUtils.h"#include<inttypes.h>usingnamespacemozilla;nsPresArena::nsPresArena(){}nsPresArena::~nsPresArena(){ClearArenaRefPtrs();#if defined(MOZ_HAVE_MEM_CHECKS)for(FreeList*entry=mFreeLists;entry!=ArrayEnd(mFreeLists);++entry){nsTArray<void*>::index_typelen;while((len=entry->mEntries.Length())){void*result=entry->mEntries.ElementAt(len-1);entry->mEntries.RemoveElementAt(len-1);MOZ_MAKE_MEM_UNDEFINED(result,entry->mEntrySize);}}#endif}/* inline */voidnsPresArena::ClearArenaRefPtrWithoutDeregistering(void*aPtr,ArenaObjectIDaObjectID){switch(aObjectID){#define PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT(name_) \ case eArenaObjectID_##name_: \ static_cast<ArenaRefPtr<name_>*>(aPtr)->ClearWithoutDeregistering(); \ return;#include"nsPresArenaObjectList.h"#undef PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORTdefault:break;}switch(aObjectID){#define PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(name_) \ case eArenaObjectID_##name_: \ MOZ_ASSERT(false, #name_ " must be declared in nsPresArenaObjectList.h "\ "with PRES_ARENA_OBJECT_SUPPORTS_ARENAREFPTR"); \ break;#include"nsPresArenaObjectList.h"#undef PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORTdefault:MOZ_ASSERT(false,"unexpected ArenaObjectID value");break;}}voidnsPresArena::ClearArenaRefPtrs(){for(autoiter=mArenaRefPtrs.Iter();!iter.Done();iter.Next()){void*ptr=iter.Key();ArenaObjectIDid=iter.UserData();ClearArenaRefPtrWithoutDeregistering(ptr,id);}mArenaRefPtrs.Clear();}voidnsPresArena::ClearArenaRefPtrs(ArenaObjectIDaObjectID){for(autoiter=mArenaRefPtrs.Iter();!iter.Done();iter.Next()){void*ptr=iter.Key();ArenaObjectIDid=iter.UserData();if(id==aObjectID){ClearArenaRefPtrWithoutDeregistering(ptr,id);iter.Remove();}}}void*nsPresArena::Allocate(uint32_taCode,size_taSize){MOZ_ASSERT(aSize>0,"PresArena cannot allocate zero bytes");MOZ_ASSERT(aCode<ArrayLength(mFreeLists));// We only hand out aligned sizesaSize=mPool.AlignedSize(aSize);FreeList*list=&mFreeLists[aCode];nsTArray<void*>::index_typelen=list->mEntries.Length();if(list->mEntrySize==0){MOZ_ASSERT(len==0,"list with entries but no recorded size");list->mEntrySize=aSize;}else{MOZ_ASSERT(list->mEntrySize==aSize,"different sizes for same object type code");}void*result;if(len>0){// Remove from the end of the mEntries array to avoid memmoving entries,// and use SetLengthAndRetainStorage to avoid a lot of malloc/free// from ShrinkCapacity on smaller sizes. 500 pointers means the malloc size// for the array is 4096 bytes or more on a 64-bit system. The next smaller// size is 2048 (with jemalloc), which we consider not worth compacting.result=list->mEntries.ElementAt(len-1);if(list->mEntries.Capacity()>500){list->mEntries.RemoveElementAt(len-1);}else{list->mEntries.SetLengthAndRetainStorage(len-1);}#if defined(DEBUG){MOZ_MAKE_MEM_DEFINED(result,list->mEntrySize);char*p=reinterpret_cast<char*>(result);char*limit=p+list->mEntrySize;for(;p<limit;p+=sizeof(uintptr_t)){uintptr_tval=*reinterpret_cast<uintptr_t*>(p);if(val!=mozPoisonValue()){MOZ_ReportAssertionFailure(nsPrintfCString("PresArena: poison overwritten; ""wanted %.16"PRIx64" ""found %.16"PRIx64" ""errors in bits %.16"PRIx64" ",uint64_t(mozPoisonValue()),uint64_t(val),uint64_t(mozPoisonValue()^val)).get(),__FILE__,__LINE__);MOZ_CRASH();}}}#endifMOZ_MAKE_MEM_UNDEFINED(result,list->mEntrySize);returnresult;}// Allocate a new chunk from the arenalist->mEntriesEverAllocated++;returnmPool.Allocate(aSize);}voidnsPresArena::Free(uint32_taCode,void*aPtr){MOZ_ASSERT(aCode<ArrayLength(mFreeLists));// Try to recycle this entry.FreeList*list=&mFreeLists[aCode];MOZ_ASSERT(list->mEntrySize>0,"object of this type was never allocated");mozWritePoison(aPtr,list->mEntrySize);MOZ_MAKE_MEM_NOACCESS(aPtr,list->mEntrySize);list->mEntries.AppendElement(aPtr);}voidnsPresArena::AddSizeOfExcludingThis(mozilla::MallocSizeOfaMallocSizeOf,nsArenaMemoryStats*aArenaStats){// We do a complicated dance here because we want to measure the// space taken up by the different kinds of objects in the arena,// but we don't have pointers to those objects. And even if we did,// we wouldn't be able to use aMallocSizeOf on them, since they were// allocated out of malloc'd chunks of memory. So we compute the// size of the arena as known by malloc and we add up the sizes of// all the objects that we care about. Subtracting these two// quantities gives us a catch-all "other" number, which includes// slop in the arena itself as well as the size of objects that// we've not measured explicitly.size_tmallocSize=mPool.SizeOfExcludingThis(aMallocSizeOf);size_ttotalSizeInFreeLists=0;for(FreeList*entry=mFreeLists;entry!=ArrayEnd(mFreeLists);++entry){mallocSize+=entry->SizeOfExcludingThis(aMallocSizeOf);// Note that we're not measuring the size of the entries on the free// list here. The free list knows how many objects we've allocated// ever (which includes any objects that may be on the FreeList's// |mEntries| at this point) and we're using that to determine the// total size of objects allocated with a given ID.size_ttotalSize=entry->mEntrySize*entry->mEntriesEverAllocated;size_t*p;switch(entry-mFreeLists){#define FRAME_ID(classname, ...) \ case nsQueryFrame::classname##_id: \ p = &aArenaStats->FRAME_ID_STAT_FIELD(classname); \ break;#define ABSTRACT_FRAME_ID(...)#include"nsFrameIdList.h"#undef FRAME_ID#undef ABSTRACT_FRAME_IDcaseeArenaObjectID_nsLineBox:p=&aArenaStats->mLineBoxes;break;caseeArenaObjectID_nsRuleNode:p=&aArenaStats->mRuleNodes;break;caseeArenaObjectID_GeckoStyleContext:p=&aArenaStats->mStyleContexts;break;#define STYLE_STRUCT(name_, checkdata_cb_) \ case eArenaObjectID_nsStyle##name_:#include"nsStyleStructList.h"#undef STYLE_STRUCTp=&aArenaStats->mStyleStructs;break;default:continue;}*p+=totalSize;totalSizeInFreeLists+=totalSize;}aArenaStats->mOther+=mallocSize-totalSizeInFreeLists;}